
/**
 * @file
 * @brief
 * @author
 * @date
 * @note
 * @see
 * @version $Id$
**/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "public.h"
#include "fdwatch.h"
#include "sockio.h"
#include "handle.h"
#include "timer.h"
#include "logout.h"

#define CFG_FILE	"./learnmore.cfg"
#define DEF_PORT	30303

static int readcfg();
static int add_session(int conn);
static int del_session(int conn);
static int readdate(struct u_session_t *session);
static int rewritedate(struct u_session_t *session);
static struct u_session_t * getsessionbyconn(int conn);
static int run();
static int sedule();

// 读取配置文件,结果保存到全局变量 g_session 中.
static int readcfg()
{
	char name[32];
	char value[32];

	FILE *fp = fopen(CFG_FILE, "r");
	if(fp==NULL) {
		perror("fopen() error");
		return -1;
	}

	while(feof(fp) == 0) {
		bzero(name, sizeof(name));
		bzero(value, sizeof(value));
		if(fscanf(fp, "%s=%s", name, value) == -1) {
			perror("fscanf() error");
			continue;
		}
		if(strcmp(name, "ip")==0){
			strncpy(g_session.ip, value, sizeof(g_session.ip)-1);
		}
		if(strcmp(name, "port") == 0) {
			g_session.port = (short)atoi(value);
		}
	}

	return 0;
}

// 添加一个用户 session
static int add_session(int conn)
{
	if(u_usercnt >= DEF_USERMAX) {
		return -1;
	}

	u_session[u_usercnt].conn=conn;
	u_usercnt++;

	return 0;
}

// 删除一个用户 session
static int del_session(int conn)
{
	int i;

	for(i=0;i<u_usercnt;i++) {
		if(u_session[i].conn==conn) {
			bcopy(&u_session[i], &u_session[u_usercnt-1], sizeof(struct u_session_t));
			u_usercnt--;
			break;
		}
	}

	return 0;
}

// 读取用户连接数据放入接收队列.
static int readdate(struct u_session_t *session)
{
	int len;
	int cnt=0;

	do{
		len = read(session->conn, session->recvbuf+session->recvlen, DEF_BUFMAX-session->recvlen);
		if(len == -1) {
			perror("read() error");
			break;
		}
		session->recvlen+=len;
		cnt+=len;
	} while(len > 0 && session->recvlen < DEF_BUFMAX);

	session->recvbuf[session->recvlen]='\0';
	fprintf(stderr, "%s\n", session->recvbuf);

	return cnt;
}

// 处理完用户消息后,发送最终结果.
int writedate(struct u_session_t *session, char *data, int len)
{
	int sndlen;

	// 发送一次,如有剩余,下次再发.
	sndlen = write(session->conn, data, len);
	if(sndlen == -1) {
		perror("write() error");
		return -1;
	}

	if(sndlen < len) {
		bcopy(session->sendbuf+session->sendlen, data+sndlen, len-sndlen);
		session->sendlen += (len-sndlen);

		fd_add(session->conn, DEF_WFD);
	}

	return 0;
}

// 可写时,发送缓存的数据.
static int rewritedate(struct u_session_t *session)
{
	// 向用户发送数据.
	int sendlen;

	if(session->sendlen > 0) {
		sendlen = write(session->conn, session->sendbuf, session->sendlen);
		if(sendlen == -1) {
			perror("write() error");
			return -1;
		}

		if(sendlen < session->sendlen) {
			memmove(session->sendbuf, session->sendbuf+sendlen, session->sendlen-sendlen);
			session->sendlen-=sendlen;

			fd_add(session->conn, DEF_WFD);
		}
	}

	return 0;
}

// 通过客户连接,得到客户的 session
static struct u_session_t * getsessionbyconn(int conn)
{
	int i;

	for(i=0; i<u_usercnt; i++) {
		if(u_session[i].conn == conn) {
			return &u_session[i];
		}
	}

	return NULL;
}

// 主处理函数
static int run()
{
	struct timeval tv;

	// 初始化描述符集超时时间.
	tv.tv_sec=0;
	tv.tv_usec=100*1000;
	fd_init(&tv);

	// 初始化计时器.
	timer_init();

	// 初始化消息句柄数组.
	msg_init();

	// 创建监听端口.
	g_session.sockfd = create_listen(NULL, g_session.port);
	if(g_session.sockfd < 0) {
		return -1;
	}

	fd_add(g_session.sockfd, DEF_RFD);

	// 循环处理连接.
	while (1) {
		// 一次监听端口处理.
		sedule();

		// 执行一次计时器函数.
		timer_exec();
	}

	return 0;
}

// 一次监听端口处理.
static int sedule()
{
	int num;
	int conn;
	struct u_session_t *session;

	// 监听端口
	num = fd_watch();
	if(num < 0) {
		return 0;
	}

	// 处理可读连接.
	while((conn = fd_get(DEF_RFD)) > 0) {
		// 新连接.
		if(conn == g_session.sockfd) {
			int newconn;

			newconn = accept_conntion(conn);
			if(newconn <= 0) {
				continue;
			}

			if(add_session(newconn) != -1) {
				fd_add(newconn, DEF_RFD);
			}

			continue;
		}

		// 接收数据.
		session = getsessionbyconn(conn);
		if(session == NULL){
			continue;
		}

		if(readdate(session) == 0) {
			fd_del(session->conn, DEF_RFD);
			del_session(session->conn);
			continue;
		}

		msg_exec(session);
	};

	// 处理可写连接.
	while((conn = fd_get(DEF_WFD)) > 0) {
		session = getsessionbyconn(conn);
		if(session == NULL){
			continue;
		}

		rewritedate(session);
	};

	return 0;
}

int main(int argc, char *argv[])
{
	g_session.port = (short)DEF_PORT;

	// 初始化日志系统.
	LOGOPEN(argv[0], 9, LOGSTDOUT);

	// 读取配置文件.
	readcfg();

	// 启动处理函数.
	run();

	return 0;
}

